/*
 * Copyright (c) 2008, Artur Emagulov
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * 27.08.2008
 * arch.h
 */

#ifndef _ARM_ARCH_H
#define _ARM_ARCH_H

#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Processor info structure
 */
typedef struct cpu_info
{
	u8 version;
	u8 family;
	u16 vendor;
	u8 variant;
	u8 arch;
	u16 partno;
	u8 rev;
	u8 cache_type;
	u8 cache_dsize;
	u8 cache_isize;
	char name[MAX_STRSIZE];
} cpu_info_t;


/**
 * Common register frame for trap/interrupt.
 * These cpu state are saved into top of the kernel stack in
 * trap/interrupt entries. Since the arguments of system calls are
 * passed via registers, the system call library is completely
 * dependent on this register format.
 */
struct cpu_regs {
	uint32_t  r0;     /*  +0 (00) */
	uint32_t  r1;     /*  +4 (04) */
	uint32_t  r2;     /*  +8 (08) */
	uint32_t  r3;     /* +12 (0C) */
	uint32_t  r4;     /* +16 (10) */
	uint32_t  r5;     /* +20 (14) */
	uint32_t  r6;     /* +24 (18) */
	uint32_t  r7;     /* +28 (1C) */
	uint32_t  r8;     /* +32 (20) */
	uint32_t  r9;     /* +36 (24) */
	uint32_t  r10;    /* +40 (28) */
	uint32_t  r11;    /* +44 (2C) */
	uint32_t  r12;    /* +48 (30) */
	uint32_t  sp;     /* +52 (34) task stack pointer */
	uint32_t  lr;     /* +56 (38) task return */
	uint32_t  svc_sp; /* +60 (3C) SVC stack pointer */
	uint32_t  svc_lr; /* +64 (40) */
	uint32_t  pc;     /* +68 (44) */
	uint32_t  cpsr;   /* +72 (48) */
};

/**
 * Kernel mode context for context switching.
 * Used by cpu_switch() routine
 */
struct kern_regs {
	uint32_t  r4;
	uint32_t  r5;
	uint32_t  r6;
	uint32_t  r7;
	uint32_t  r8;
	uint32_t  r9;
	uint32_t  r10;
	uint32_t  r11;
	uint32_t  sp;
	uint32_t  lr;
};

/* TODO FPU Registers context support */
#ifdef CONFIG_FPU
/**
 * FPU register for fsave/frstor
 */
struct fpu_regs {

};
#endif

/**
 * Processor context
 */
struct context {
	/**
	 * Kernel context is mandatory,
	 * because of context switch appears in kernel mode
	 * and uses standard return procedure which restores
	 * user context.
	 */
	vaddr_t				k_stack_top;	/* kernel stack top */
	vaddr_t				u_stack_top;	/* user stack top */
	struct kern_regs	kregs;			/* kernel mode registers */
	struct cpu_regs		*uregs;			/* user mode registers */
	struct cpu_regs		*saved_regs;	/* saved user mode registers */
#ifdef CONFIG_FPU
	struct fpu_regs		*fregs;			/* co-processor registers */
#endif
};

typedef struct context *context_t;	/* context id */

#define ARCH_TS_PEN_INT	28	/* Touchscreen pen-down event interrupt */
#define ARCH_ETH_INT		27	/* Ethernet interface interrupt */
#define ARCH_CPPLD_INT	26	/* Interrupt from secondary interrupt controller, see Secondary interrupt controller registers. */
#define ARCH_AACI_INT		25	/* Audio interface interrupt */
#define ARCH_MMCI1_INT	24	/* MultiMedia card interface 1 */
#define ARCH_MMCI0_INT	23	/* MultiMedia card interface 0 */
#define ARCH_CLDC_INT		22	/* Display controller interrupt */
#define ARCH_LM_LL1_INT	10	/* Logic module low-latency interrupt 1 */
#define ARCH_LM_LL0_INT	9	/* Logic module low-latency interrupt 0 */
#define ARCH_RTC_INT		8	/* Real time clock interrupt */
#define ARCH_TIMER2_INT	7	/* Counter-timer 2 interrupt */
#define ARCH_TIMER1_INT	6	/* Counter-timer 1 interrupt */
#define ARCH_TIMER0_INT	5	/* Counter-timer 0 interrupt */
#define ARCH_MOUSE_INT	4	/* Mouse interrupt */
#define ARCH_KBD_INT		3	/* Keyboard interrupt */
#define ARCH_UART1_INT	2	/* UART 1 interrupt */
#define ARCH_UART0_INT	1	/* UART 0 interrupt */
#define ARCH_SOFT_INT		0	/* Software interrupt */

/* Which interrupt is used for periodic scheduling */
#define ARCH_PERIODIC_INT	ARCH_TIMER1_INT

/**
 * Bit values
 */
#define ARCH_TS_PEN_INT_BIT	0x10000000	/* Touchscreen pen-down event interrupt */
#define ARCH_ETH_INT_BIT		0x8000000	/* Ethernet interface interrupt */
#define ARCH_CPPLD_INT_BIT	0x4000000	/* Interrupt from secondary interrupt controller, see Secondary interrupt controller registers. */
#define ARCH_AACI_INT_BIT	0x2000000	/* Audio interface interrupt */
#define ARCH_MMCI1_INT_BIT	0x1000000	/* MultiMedia card interface 1 */
#define ARCH_MMCI0_INT_BIT	0x800000	/* MultiMedia card interface 0 */
#define ARCH_CLDC_INT_BIT	0x400000	/* Display controller interrupt */
#define ARCH_LM_LL1_INT_BIT	0x400	/* Logic module low-latency interrupt 1 */
#define ARCH_LM_LL0_INT_BIT	0x200	/* Logic module low-latency interrupt 0 */
#define ARCH_RTC_INT_BIT		0x100	/* Real time clock interrupt */
#define ARCH_TIMER2_INT_BIT	0x80	/* Counter-timer 2 interrupt */
#define ARCH_TIMER1_INT_BIT	0x40	/* Counter-timer 1 interrupt */
#define ARCH_TIMER0_INT_BIT	0x20	/* Counter-timer 0 interrupt */
#define ARCH_MOUSE_INT_BIT	0x10	/* Mouse interrupt */
#define ARCH_KBD_INT_BIT		0x8	/* Keyboard interrupt */
#define ARCH_UART1_INT_BIT	0x4	/* UART 1 interrupt */
#define ARCH_UART0_INT_BIT	0x2	/* UART 0 interrupt */
#define ARCH_SOFT_INT_BIT	0x1	/* Software interrupt */

#define ARCH_INT_MASK	0x1FC007FF	/* 0b00011111110000000000011111111111 */

/**
 *  MMU definitions
 */
#define PTE_L1_FAULT		0x0
#define PTE_L1_COARSE	0x1
#define PTE_L1_SECTION	0x2
#define PTE_L1_FINE		0x3

#define PTE_L2_FAULT		0x0
#define PTE_L2_LARGE		0x1
#define PTE_L2_SMALL		0x2
#define PTE_L2_TINY		0x3

/**
 * Page AP definitions, each name consists of PTE_AP_<SVC_PERM>_<USER_PERM>,
 * where SVC_PERM - System permission,
 * and USER_PERM - User mode permission
 */
#define PTE_AP_NO_NO		0x0
#define PTE_AP_RW_NO		0x1
#define PTE_AP_RW_RO		0x2
#define PTE_AP_RW_RW		0x3

#define PTE_L2_FINE_MASK 0x000FFF000
#define PTE_L2_COARSE_MASK 0x000FFC00
#define PTE_L1_MASK 		0xFFF00000
#define PTE_L2_TYPE_MASK		0x3
#define PTE_L1_TYPE_MASK		0x3

#define PTE_L2_COARSE_IDX(x)	((x & 0x000FF000) >> 12)
#define PTE_L2_FINE_IDX(x)	((x & PTE_L2_FINE_MASK) >> 12)
#define PTE_L1_IDX(x)		((x & PTE_L1_MASK) >> 20)
#define PTE_L1_IDX_ADDR(x)	((x & PTE_L1_MASK) >> 18)

/**/
#define V_IO_BASE			0xF0000000		/* Virtual addres of IO region */
#define V_IO_SIZE			0x0F000000		/* Size of IO region */
#define P_IO_BASE			0x10000000		/* Physical address of IO region */

#define bus_to_virt(pa) (void *)((unsigned long)pa + (unsigned long)V_IO_BASE - (unsigned long)P_IO_BASE)
typedef void (*irqfn_t)(struct cpu_regs *r);

#ifdef __cplusplus
}
#endif

#endif /* !_ARM_ARCH_H */
